/******************************************************************************

  File Name     : mp_allocator.h
  Version       : Initial Draft
  Author        : tongzhilin
  Created       : 2020/8/10
  Last Modified :
  Description   : mp_allocator, alloc aligned addr for container, now aligned vector use this
    code modify from STL allocator class
  Function List :
  History       :
  1.Date        : 2020/8/10
    Author      : tongzhilin
    Modification: Created file

******************************************************************************/
#pragma once
#include "mp_common.h"

template<typename _Type, size_t _align, bool _Nothrow = true>
class mp_allocator : public std::allocator<_Type>
{
public:
    typedef size_t          size_type;
    typedef std::ptrdiff_t  difference_type;
    typedef _Type*          pointer;
    typedef const _Type*    const_pointer;
    typedef _Type&          reference;
    typedef const _Type&    const_reference;
    typedef _Type           value_type;

    template<typename _Type2>
    struct rebind
    {
        typedef mp_allocator<_Type2, _align> other;
    };

    typedef std::true_type propagate_on_container_move_assignment;

    mp_allocator() { }
    template<typename _Type2>
    mp_allocator(const mp_allocator<_Type2, _align>&) { }
    ~mp_allocator() { }

    pointer allocate(size_type __n, const void* = 0)
    {
        if (__n > this->max_size()) {
            MP_ASSERT(false);
        }

//#ifdef HAS_POSIX_MEMALIGN
        _Type* result;
        if (posix_memalign(&(void *&)result, _align, __n * sizeof(_Type)) != 0)
        {
            if (_Nothrow)
            {
                //don't throw catch
                return nullptr;
            }
            else
            {
                MP_ASSERT(false);
            }
        }
        return result;
//#elif defined(HAS_MEMALIGN)
        //return (_Type*)memalign(_align, __n * sizeof(_Type));
//#else
        //return (_Type*)malloc(__n * sizeof(_Type));
//#endif
    }

    // __p is not permitted to be a null pointer.
    void deallocate(pointer __p, size_type)
    {
        free((void *)__p);
    }
};

template<typename _Type1, typename _Type2, size_t _Align1, size_t _Align2>
inline bool
operator==(const mp_allocator<_Type1, _Align1>&, const mp_allocator<_Type2, _Align2>&)
{
    return true;
}

template<typename _Type1, typename _Type2, size_t _Align1, size_t _Align2>
inline bool
operator!=(const mp_allocator<_Type1, _Align1>&, const mp_allocator<_Type2, _Align2>&)
{
    return false;
}

//allocator<void> specialization.
//void的特化版本
template<size_t _align>
class mp_allocator<void, _align>
{
public:
    typedef size_t              size_type;
    typedef std::ptrdiff_t      difference_type;
    typedef void*               pointer;
    typedef const void*         const_pointer;
    typedef void                value_type;

    template<typename _Type2>
    struct rebind
    {
        typedef mp_allocator<_Type2, _align> other;
    };

    typedef std::true_type propagate_on_container_move_assignment;
};


